package com.llcbenwu.security;

//import com.llcbenwu.filter.VerificationFilter;

import com.llcbenwu.filter.SmsCodeFilter;
import com.llcbenwu.filter.VerificationFilter;
import com.llcbenwu.session.LlcExpiredSessionStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.social.security.SpringSocialConfigurer;

import javax.annotation.Resource;
import javax.sql.DataSource;

/**
 * @author lilinchun
 * @date 2021/10/23 0023 15:16
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {


    /**
     * 成功认证
     */
    @Autowired
    private AuthenticationSuccessHandler llcAuthenticationSuccessHandler;

    /**
     * 失败认证
     */
    @Autowired
    private AuthenticationFailureHandler llcAuthentiationFailHandler;
    /**
     * 注入一个数据源进来
     */
    @Autowired
    private DataSource dataSource;
    /**
     * 获取用户信息
     */
    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private SmsCodeSecurityConfig smsCodeSecurityConfig;

    @Resource
    private SpringSocialConfigurer llcSocialSecurityConfig;

    @Resource
    private LogoutSuccessHandler logoutSuccessHandler;
    /**
     * 配置记住我存取器配置
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
//          tokenRepository.setCreateTableOnStartup(true); //启用时创建一张表记录用户使用的token 第一次启动成功之后就可以注释了
        return tokenRepository;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    /**
     * springSecurity的配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //认证码过滤
        VerificationFilter verificationFilter = new VerificationFilter();
        verificationFilter.setAuthenticationFailureHandler(llcAuthentiationFailHandler);
        verificationFilter.afterPropertiesSet();
        //短信认证
        SmsCodeFilter smsCodeFilter = new SmsCodeFilter();
        smsCodeFilter.setAuthenticationFailureHandler(llcAuthentiationFailHandler);
        smsCodeFilter.afterPropertiesSet();

        http.addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class) //先去认证短信过滤
                .addFilterBefore(verificationFilter, UsernamePasswordAuthenticationFilter.class) //让请求先经过我们自定义的过滤器
                .formLogin()  //表单登录
                .loginPage("/authentication/require") //如果没有认证需要跳转的url
                .loginProcessingUrl("/authentication/form") //告诉UsernamePasswordAuthenticationFilter 处理这个请求
                .successHandler(llcAuthenticationSuccessHandler) //成功之后进入自定义请求业务接口
                .failureHandler(llcAuthentiationFailHandler)//失败之后进入自定义请求业务接口
                .and()
                .apply(llcSocialSecurityConfig)
                .and()
                .sessionManagement()
                .invalidSessionUrl("/session/invalid") //session失效的时候跳转的路径
                .maximumSessions(1) //一个用户session最大设置数
                .maxSessionsPreventsLogin(true) //只允许先前一个登录后一个不能登录
                .expiredSessionStrategy(new LlcExpiredSessionStrategy())  //session并发
                .and()
                .and()
                .rememberMe()
                .tokenRepository(persistentTokenRepository()) //获取数据源的一些信息
                .tokenValiditySeconds(SecurityProperies.REMBERMESECONDS) //配置cookie的过期时间
                .userDetailsService(userDetailsService) //获取用户信息
                .and()
                .logout()
                .logoutUrl("/signOut")  //退出登录的url
                .logoutSuccessHandler(logoutSuccessHandler) //退出成功之后进入到这个页面
                .deleteCookies("JSESSIONID")  //清理浏览器cookies
//        http.httpBasic()
                .and()
                .authorizeRequests() //下面都是授权
                .antMatchers("/llc-signIn.html", "/authentication/require",
                        "/favicon.ico", "/code/*","/user/regist",
                        "/llc-signUp.html","/session/invalid","/llc-signOut.html").permitAll()  //不需要认证的网页
                .anyRequest()  //任何请求
                .authenticated()
                .and().csrf().disable()
                .apply(smsCodeSecurityConfig);  //将自己的过滤配置加入进配置
    }


    /**
     * 配置不需要验证
     * @param http
     * @throws Exception
     */
//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        http.authorizeRequests()
//                .anyRequest().permitAll().and().logout().permitAll().and()
//                .csrf().disable();//配置不需要登录验证
//    }
}
